﻿using System.Collections.Generic;

namespace Gamelight
{
	/// <summary>
	/// Just a buncha useful helper functions.
	/// </summary>
	public static class Util
	{
		private static System.Random random = new System.Random();

		/// <summary>
		/// Caps the value into the given range. 
		/// </summary>
		public static int EnsureRange(int value, int min, int max)
		{
			if (value < min) return min;
			if (value > max) return max;
			return value;
		}

		/// <summary>
		/// Caps the value into the given range. 
		/// </summary>
		public static double EnsureRange(double value, double min, double max)
		{
			if (value < min) return min;
			if (value > max) return max;
			return value;
		}

		/// <summary>
		/// Shuffles the given list in place. 
		/// </summary>
		public static void ShuffleList<T>(IList<T> list)
		{
			int length = list.Count;
			T t;
			int t_index;
			for (int i = 0; i < length; ++i)
			{
				t_index = random.Next(length);
				t = list[t_index];
				list[t_index] = list[i];
				list[i] = t;
			}
		}

		/// <summary>
		/// Returns a 2-dimensional grid of type T filled with the default value of T
		/// e.g. 0's, nulls, falses
		/// </summary>
		public static T[][] MakeGrid<T>(int width, int height)
		{
			return MakeGrid(width, height, default(T));
		}

		/// <summary>
		/// Returns a 2-dimensional grid of type T filled with the given value in each cell.
		/// </summary>
		public static T[][] MakeGrid<T>(int width, int height, T defaultValue)
		{
			List<T[]> columns = new List<T[]>();
			for (int x = 0; x < width; ++x)
			{
				T[] column = new T[height];

				for (int y = 0; y < height; ++y)
				{
					column[y] = defaultValue;
				}
				columns.Add(column);
			}
			return columns.ToArray();
		}

		/// <summary>
		/// Returns a random item in the list.
		/// </summary>
		public static T PickRandom<T>(IList<T> list)
		{
			int i = random.Next(list.Count);
			return list[i];
		}

		/// <summary>
		/// Returns and removes a random item in the list.
		/// </summary>
		public static T PopRandom<T>(List<T> list)
		{
			int i = random.Next(list.Count);
			T item = list[i];
			list.RemoveAt(i);
			return item;
		}

		/// <summary>
		/// Returns the item in the dictionary at the given key. If the key doesn't exist, the default value is used. 
		/// e.g. null, 0, or false.
		/// </summary>
		public static V GetOrDefault<K, V>(this IDictionary<K, V> dict, K key)
		{
			V output;
			if (!dict.TryGetValue(key, out output))
			{
				return default(V);
			}
			return output;
		}

		/// <summary>
		/// Returns the item in the dictionary at the given key. If the key doesn't exist, the given default value is used instead. 
		/// </summary>
		public static V GetOrDefault<K, V>(this IDictionary<K, V> dict, K key, V defaultValue)
		{
			V output;
			if (!dict.TryGetValue(key, out output))
			{
				return defaultValue;
			}
			return output;
		}

		/// <summary>
		/// Determine if two circle bodies have collided. 
		/// </summary>
		public static bool IsCircularIntersection(int x1, int y1, int r1, int x2, int y2, int r2)
		{
			int dx = x1 - x2;
			int dy = y1 - y2;
			int minD = r1 + r2;
			return dx * dx + dy * dy < minD * minD;
		}

		/// <summary>
		/// Determine if two circle bodies have collided. 
		/// </summary>
		public static bool IsCircularIntersection(double x1, double y1, double r1, double x2, double y2, double r2)
		{
			double dx = x1 - x2;
			double dy = y1 - y2;
			double minD = r1 + r2;
			return dx * dx + dy * dy < minD * minD;
		}

		/// <summary>
		/// Determine if two rectangular bodies have collided.
		/// </summary>
		public static bool IsRectangularIntersection(int left1, int top1, int right1, int bottom1, int left2, int top2, int right2, int bottom2)
		{
			return !(
				left1 > right2 ||
				right1 < left2 ||
				top1 > bottom2 ||
				bottom1 < top2);
		}

		/// <summary>
		/// Determine if two rectangular bodies have collided.
		/// </summary>
		public static bool IsRectangularIntersection(double left1, double top1, double right1, double bottom1, double left2, double top2, double right2, double bottom2)
		{
			return !(
				left1 > right2 ||
				right1 < left2 ||
				top1 > bottom2 ||
				bottom1 < top2);
		}

		/// <summary>
		/// Attempt to parse an int from a string. Return the given value upon failure.
		/// </summary>
		public static int ParseIntOrDefault(string value, int defaultValue)
		{
			int output;
			if (int.TryParse(value, out output))
			{
				return output;
			}
			return defaultValue;
		}

		/// <summary>
		/// Attempt to parse an int from a string. Return 0 upon failure.
		/// </summary>
		public static int ParseIntOrDefault(string value)
		{
			int output;
			if (int.TryParse(value, out output))
			{
				return output;
			}
			return 0;
		}

		/// <summary>
		/// Attempt to parse a double from a string. Return the given value upon failure.
		/// </summary>
		public static double ParseDoubleOrDefault(string value, double defaultValue)
		{
			double output;
			if (double.TryParse(value, out output))
			{
				return output;
			}
			return defaultValue;
		}

		/// <summary>
		/// Attempt to parse a double from a string. Return 0.0 upon failure.
		/// </summary>
		public static double ParseDoubleOrDefault(string value)
		{
			double output;
			if (double.TryParse(value, out output))
			{
				return output;
			}
			return 0.0;
		}
	}
}
